package com.mcxx.modules.common.service;

import com.mcxx.common.exception.BizException;
import com.mcxx.modules.base.service.read.AreaReadService;
import com.mcxx.modules.statistics.dto.StatisticDTO;
import com.mcxx.modules.statistics.param.StatisticParam;
import com.mcxx.modules.system.entity.AreaSalvationEntity;
import com.mcxx.modules.system.service.read.SalvationRuleReadService;
import com.mcxx.util.AreaUtil;
import com.mcxx.util.CommonUtil;
import com.mcxx.util.Constant;
import com.mcxx.util.FailureCode;
import com.yinhai.ta404.component.org.orguser.area.entity.TaAreaPo;
import com.yinhai.ta404.core.security.vo.UserAccountVo;
import com.yinhai.ta404.core.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;


public abstract class StatisticService extends BaseService {
    @Autowired
    protected AreaUtil areaUtil;
    @Autowired
    private AreaReadService areaReadService;
    @Autowired
    private SalvationRuleReadService salvationRuleReadService;


    public abstract List<? extends StatisticDTO> getStatistic(StatisticParam param, UserAccountVo accountVo,
                                                              String standType);
    public abstract void fillSalvation(StatisticDTO dto, List<String> standards, List<AreaSalvationEntity> salivations);


    public String commonStatisticStart(StatisticParam param, UserAccountVo accountVo, List<TaAreaPo> taAreaPos,
                                       List<Integer> levels){
        if(CommonUtil.invalidArgs(param.getMonth()) || param.getMonth().length() != 6) {
            throw new BizException(FailureCode.ERR_10001);
        }


        if(CommonUtil.invalidArgs(param.getAreaCode())){
            param.setAreaCode(accountVo.getAreaCode());
        }



        TaAreaPo curTaAreaPo = null;
        StringBuilder name= new StringBuilder();
        List<String> areaCodes = areaUtil.getNodeTreePathFromRoot(param.getAreaCode());
        for(String code : areaCodes){
            TaAreaPo taAreaPro = areaReadService.getAreaByCode(code);
            if(null != taAreaPro)
                name.append(taAreaPro.getAreaName());

            if(code.equals(param.getAreaCode())){
                curTaAreaPo = taAreaPro;
            }
        }

        if(null == curTaAreaPo){
            throw new BizException(FailureCode.ERR_100001);
        }

        name.append(param.getMonth().substring(0, 4)).append("年").append(param.getMonth().substring(4)).append("月");



        if(null != taAreaPos)
            taAreaPos.add(curTaAreaPo);

        if(null != levels && null != taAreaPos){
            levels.add(curTaAreaPo.getAreaLevel());
            if(curTaAreaPo.getAreaLevel().equals(Constant.AreaLevel.PROVINCE)){
                taAreaPos.addAll(areaReadService.getChildrenByLevel(
                        areaUtil.getValidCode(curTaAreaPo.getAreaCode(), curTaAreaPo.getAreaLevel()),
                        Arrays.asList(curTaAreaPo.getAreaLevel() + 1, curTaAreaPo.getAreaLevel() + 2)));
                levels.add(curTaAreaPo.getAreaLevel() + 1);
                levels.add(curTaAreaPo.getAreaLevel() + 2);
            }
            else{
                if (curTaAreaPo.getAreaLevel() < Constant.AreaLevel.COMMUNITY){
                    taAreaPos.addAll(areaReadService.getChildrenByLevel(
                            areaUtil.getValidCode(curTaAreaPo.getAreaCode(), curTaAreaPo.getAreaLevel()),
                            Collections.singletonList(curTaAreaPo.getAreaLevel() + 1)));
                    levels.add(curTaAreaPo.getAreaLevel() + 1);
                }
            }

            if(taAreaPos.isEmpty() || levels.isEmpty() || name.toString().isEmpty()){
                throw new BizException(FailureCode.ERR_100002);
            }
        }

        return name.toString();
    }


    public void commonStatisticEnd(String name, List<String> standards, List<TaAreaPo> taAreaPos, List<Integer> levels,
                                   List<? extends StatisticDTO> results){

        List<StatisticDTO> notExistArea = new ArrayList<>();
        HashSet<String> codes = new HashSet<String>();

        for(StatisticDTO dto : results) {

            Optional<TaAreaPo> taAreaPo = taAreaPos.stream()
                    .filter(area -> area.getAreaCode().equals(dto.getAreaCode())).findFirst();
            if(!taAreaPo.isPresent()) {
                notExistArea.add(dto);
                continue;
            }

            dto.setAreaName(taAreaPo.get().getAreaName());
            dto.setArea(taAreaPo.get().getAreaName());
            dto.setAreaLevel(taAreaPo.get().getAreaLevel());
            codes.add(areaUtil.getSuperLevelAreaCode(dto.getAreaCode(), Constant.AreaLevel.COUNTY));
        }
        results.removeAll(notExistArea);


        List<AreaSalvationEntity> areaSalvations = null;
        if(null != standards && !standards.isEmpty())
            areaSalvations = salvationRuleReadService.getAreaSalivations(
                    new ArrayList<String>(codes), standards);


        int maxLevel = levels.get(levels.size() - 1);
        for(StatisticDTO statisDTO : results){
            statisDTO.setTitle(name);


            if(null != areaSalvations){
                List<AreaSalvationEntity> salivations = getAreaSalvations(statisDTO, standards, areaSalvations);
                if(!salivations.isEmpty())
                    this.fillSalvation(statisDTO, standards, salivations);
            }


            if(statisDTO.getAreaLevel() < maxLevel){
                statisDTO.setAreaName(statisDTO.getAreaName()+"合计");
                statisDTO.setArea(statisDTO.getArea()+"合计");
                statisDTO.setIsHe("1");
            }else{
                statisDTO.setIsHe("0");
            }
        }
    }


    private List<AreaSalvationEntity>  getAreaSalvations(StatisticDTO statisDTO, List<String> standards,
                                                         List<AreaSalvationEntity> areaSalvations){
        List<AreaSalvationEntity> salivations = null;
        if(statisDTO.getAreaLevel() < Constant.AreaLevel.COUNTY){

            String validCode = areaUtil.getValidCode(statisDTO.getAreaCode(), statisDTO.getAreaLevel());
            List<AreaSalvationEntity> tempSalivations = areaSalvations.stream()
                    .filter(item -> {
                        return statisDTO.getAreaCode().startsWith(validCode);
                    }).collect(Collectors.toList());


            salivations = new ArrayList<AreaSalvationEntity>();
            for(String standard : standards){
                Double totalMoney = 0D;
                int num = 0;
                for(AreaSalvationEntity salivation : tempSalivations){
                    if(salivation.getType().equals(standard) && salivation.getAreaCode().startsWith(validCode)){
                        totalMoney += salivation.getStandardMoney();
                        num++;
                    }
                }

                AreaSalvationEntity temp = new AreaSalvationEntity();
                temp.setAreaCode(statisDTO.getAreaCode());
                temp.setType(standard);
                if(num > 0)
                    temp.setStandardMoney(Math.round(totalMoney / num * 100) / 100D);
                else
                    temp.setStandardMoney(0D);
                salivations.add(temp);
            }
        }
        else{

            String finalAreaCode = statisDTO.getAreaLevel() == Constant.AreaLevel.COUNTY
                    ? statisDTO.getAreaCode()
                    : statisDTO.getAreaCode().substring(0, 6)+"000000";
            salivations = areaSalvations.stream()
                    .filter(item -> {
                        return finalAreaCode.equals(item.getAreaCode());
                    }).collect(Collectors.toList());
        }

        return salivations;
    }

}
